package cate.game.framework;

import cate.game.client.ClientContext;
import cate.game.client.request.ClientRequestHandler;
import cate.game.role.Role;
import cp.solution.util.concurrent.ThreadFactoryImpl;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.Random;
import java.util.concurrent.*;

@Slf4j
public class ThreadShare {

    private static class ThreadShareHolder {
        private static final ThreadShare INSTANCE = new ThreadShare();
    }

    public static ThreadShare instance() {
        return ThreadShareHolder.INSTANCE;
    }

    private static final int MAX_QUEUE_SIZE = 2000;
    private static final int POOL_SIZE = 8;

    protected ExecutorService[] esPools = new ExecutorService[POOL_SIZE];

    public ExecutorService getExecutor(int index) {
        return esPools[index % POOL_SIZE];
    }

    public ThreadShare() {
        for (int i = 0; i < POOL_SIZE; i++) {
            esPools[i] = new ThreadPoolExecutor(1, 1,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(), new ThreadFactoryImpl("thread-share-" + i + "-"));
        }
        log.debug("共享线程池初始化完成");
    }

    public boolean exe(int index, Runnable r){
        return exe(index, r, false);
    }

    public boolean exe(int index, Runnable r, boolean checkSize) {
        ExecutorService es = getExecutor(index);
        if (Objects.nonNull(es)) {
            try{
                if (checkSize && ((ThreadPoolExecutor) es).getQueue().size() >= MAX_QUEUE_SIZE) {
                    return false;
                }
            }catch(Exception e){
                //报错就让他执行
                log.error("怎么报错了啊", e);
            }
            es.execute(r);
        }
        return true;
    }

    public boolean roleExe(ClientContext cc, Runnable r, String msg) {
        if (cc == null) {
            return false;
        }
        if(!exe(calcIndex(cc.getRole()), r, true)){
            log.info("{}的消息{}被拒绝处理了", cc.getRole() == null ? "某个人" : cc.getRole().getBase().name, msg);
            return false;
        }
        return true;
    }

    public void exe(ClientContext cc, Runnable r) {
        if(cc == null) {
            exe(0, r, false);
        } else {
            exe(cc.getRole(), r);
        }
    }

    public void exe(Role role, Runnable r) {
        exe(calcIndex(role), r, false);
    }

    private int calcIndex(Role role) {
        return role == null ? new Random().nextInt(POOL_SIZE) : Math.abs(role.getUid().hashCode());
    }

    public static void logStatus(){
        if (!ClientRequestHandler.countEnabled()) {
            return;
        }
        try{
            int totalNum = 0;
            for(int i=0; i<POOL_SIZE; ++i){
                ThreadPoolExecutor executor = ((ThreadPoolExecutor) ThreadShare.instance().esPools[i]);
                int queueSize = executor.getQueue().size();
                totalNum += queueSize;
            }
            if (totalNum > 0) {
                log.info("本次堆积了共{}条请求, total reqs={}",totalNum, ClientRequestHandler.getReqsCount());
            }
        }catch(Exception e){
            //
        }
    }

    private static final int ALMOST_FULL_SIZE = MAX_QUEUE_SIZE >> 1;
    public static boolean almostFull(){
        boolean almostFull = false;
        try{
            ThreadPoolExecutor executor = ((ThreadPoolExecutor) ThreadShare.instance().esPools[0]);
            return executor != null && executor.getQueue().size() >= ALMOST_FULL_SIZE;
        }catch (Exception e){
            //
        }
        return almostFull;
    }
}
